package com.hd123.rumba.gwt.widget2e.client.dialog;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.hd123.rumba.gwt.widget2.client.action.RActionFactory;
import com.hd123.rumba.gwt.widget2.client.button.RButton;
import com.hd123.rumba.gwt.widget2.client.dialog.RDialog;
import com.hd123.rumba.gwt.widget2.client.dialog.RMsgBox;
import com.hd123.rumba.gwt.widget2.client.form.RForm;
import com.hd123.rumba.gwt.widget2.client.grid.RGrid;
import com.hd123.rumba.gwt.widget2.client.grid.RGridClickListener;
import com.hd123.rumba.gwt.widget2.client.grid.RGridColumnDef;
import com.hd123.rumba.gwt.widget2.client.grid.RGridPageDataProvider;
import com.hd123.rumba.gwt.widget2.client.grid.RPagingGrid;
import com.hd123.rumba.gwt.widget2.client.grid.RPagingGridListener;
import com.hd123.rumba.gwt.widget2.client.toolbar.RToolbar;
import com.hd123.rumba.gwt.widget2.client.toolbar.RToolbarButton;

/**
 * 浏览对话框
 * 
 * @author LiQi
 * 
 */
public class RBrowserDialog extends RDialog {

  /** 样式 */
  private static final String STYLENAME_FILTERPANEL = "rb-BrowserDialog-filterpanel";

  /** 每页记录数 */
  private static final int DEFAULT_PAGE_SIZE = 15;

  /** 筛选方式：不筛选 */
  public static final int FILTER_STYLE_NONE = 0;

  /** 筛选方式：筛选面板 */
  public static final int FILTER_STYLE_PANEL = 1;

  /** 筛选方式：筛选对话框 */
  public static final int FILTER_STYLE_DIALOG = 2;

  /** 根面板 */
  private VerticalPanel root;

  /** 工具栏 */
  private RToolbar toolbar;

  /** 确定按钮 */
  private RToolbarButton okButton;

  /** 筛选按钮 */
  private RToolbarButton filterButton;

  /** 表格 */
  private RGrid grid;

  /** 翻页表格 */
  private RPagingGrid pagingGrid;

  /** 表格列标题 */
  private String[] columnCaptions;

  /** 回调 */
  private RBrowserCallback browserCallback;

  /** 筛选方式，取值范围为FILTER_STYLE_* */
  private int filterStyle = FILTER_STYLE_NONE;

  /** 筛选面板 */
  private HorizontalPanel filterPanel;

  /** 筛选对话框 */
  private RFilterDialog filterDialog;

  /** 筛选界面回调 */
  private RFilterCallback filterCallback;

  /** 是否只能单选 */
  private boolean singleSelection = true;

  /**
   * @param caption
   *          窗口标题
   * @param columnCaptions
   *          表格列标题
   * @param callback
   *          回调
   */
  public RBrowserDialog(String caption, String[] columnCaptions, RBrowserCallback callback) {
    this(caption, columnCaptions, callback, null);
  }

  /**
   * @param columnCaptions
   *          表格列标题
   * @param callback
   *          回调
   */
  public RBrowserDialog(String[] columnCaptions, RBrowserCallback callback) {
    this(null, columnCaptions, callback, null);
  }

  /**
   * @param caption
   *          窗口标题
   * @param columnCaptions
   *          表格列标题
   * @param callback
   *          回调
   */
  public RBrowserDialog(String caption, String[] columnCaptions, RBrowserWithFilterCallback callback) {
    this(caption, columnCaptions, (RBrowserCallback) callback, (RFilterCallback) callback);
  }

  /**
   * @param columnCaptions
   *          表格列标题
   * @param callback
   *          回调
   */
  public RBrowserDialog(String[] columnCaptions, RBrowserWithFilterCallback callback) {
    this(null, columnCaptions, callback);
  }

  /**
   * @param columnCaptions
   *          表格列标题
   * @param browserCallback
   *          浏览对话框回调
   * @param filterCallback
   *          筛选回调，若只需要代码和名称的筛选，可使用RCodeNameFilterCallbackImpl
   */
  public RBrowserDialog(String[] columnCaptions, RBrowserCallback browserCallback,
      RFilterCallback filterCallback) {
    this(null, columnCaptions, browserCallback, filterCallback);
  }

  /**
   * @param caption
   *          窗口标题
   * @param columnCaptions
   *          表格列标题
   * @param browserCallback
   *          浏览对话框回调
   * @param filterCallback
   *          筛选回调，若只需要代码和名称的筛选，可使用RCodeNameFilterCallbackImpl
   */
  public RBrowserDialog(String caption, String[] columnCaptions, RBrowserCallback browserCallback,
      RFilterCallback filterCallback) {
    this(columnCaptions);
    setCaption(caption);
    setBrowserCallback(browserCallback);
    setFilterCallback(filterCallback);
  }

  /**
   * 本构造方法不允许外界调用，是因为对使用者来说，browserCallback是必须的，所以要求使用者在构造方法中传入。
   * 而本方法允许派生类调用时因为允许派生类对browserCallback做一些改变 ，参见
   * {@link RSimpleBrowserDialog}
   * 
   * @param columnCaptions
   *          表格列标题
   */
  protected RBrowserDialog(String[] columnCaptions) {
    super();
    setColumnCaptions(columnCaptions);

    root = new VerticalPanel();
    root.setWidth("100%");

    buildToolbar();
    buildGrid();

    setWidget(root);
  }

  /**
   * 构造工具栏
   * 
   */
  private void buildToolbar() {
    toolbar = new RToolbar();

    okButton = new RToolbarButton(RActionFactory.makeOkAction(new OKButtonHandler()));
    toolbar.add(okButton);

    // 取消按钮
    toolbar.add(new RToolbarButton(RActionFactory.makeCancelAction(new ClickHandler() {
      public void onClick(ClickEvent event) {
        hide();
      }
    })));

    // 刷新按钮
    toolbar.add(new RToolbarButton(RActionFactory.makeRefreshAction(new ClickHandler() {
      public void onClick(ClickEvent event) {
        pagingGrid.forceRefresh();
      }
    })));

    root.add(toolbar);
  }

  /**
   * 根据filterStyle构造筛选界面
   * 
   */
  private void buildFilterUI() {
    switch (filterStyle) {
    case FILTER_STYLE_NONE:
      if (filterPanel != null)
        //        filterPanel.setVisible(false);
        root.remove(filterPanel);
      if (filterButton != null)
        filterButton.setVisible(false);
      break;

    case FILTER_STYLE_PANEL:
      buildFilterPanel();
      if (filterButton != null)
        filterButton.setVisible(false);
      break;

    case FILTER_STYLE_DIALOG:
      buildFilterDialog();
      if (filterPanel != null)
        root.remove(filterPanel);
      //        filterPanel.setVisible(false);
      break;
    }
  }

  /**
   * 构造筛选面板
   * 
   */
  private void buildFilterPanel() {
    if (filterPanel != null) {
      if (!filterPanel.isAttached())
        root.insert(filterPanel, 1);
      return;
    }

    if (filterCallback == null)
      throw new NullPointerException("filterStyle为FILTER_STYLE_PANEL而filterCallback为null，无法构造筛选界面");

    filterPanel = new HorizontalPanel();
    filterPanel.setStyleName(STYLENAME_FILTERPANEL);
    filterPanel.setWidth("100%");
    root.insert(filterPanel, 1);

    // 查询条件表单
    RForm filterForm = new RForm();
    filterCallback.buildConditions(filterForm);
    filterPanel.add(filterForm);

    // 按钮面板
    HorizontalPanel buttonPanel = new HorizontalPanel();
    buttonPanel.setSpacing(4);
    filterPanel.add(buttonPanel);
    filterPanel.setCellWidth(buttonPanel, "110px");

    // 查询按钮
    RButton queryButton = new RButton("查询");
    queryButton.setWidth("50px");
    queryButton.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event) {
        filterCallback.onQuery();
        pagingGrid.forceRefreshAndGotoFirstPage();
      }
    });
    buttonPanel.add(queryButton);

    // 清除按钮
    RButton clearButton = new RButton("清除");
    clearButton.setWidth("50px");
    clearButton.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event) {
        filterCallback.clearConditions();
      }
    });
    buttonPanel.add(clearButton);
  }

  /**
   * 构造筛选对话框
   * 
   */
  private void buildFilterDialog() {
    if (filterDialog != null)
      return;

    if (filterCallback == null)
      throw new NullPointerException("filterStyle为FILTER_STYLE_DIALOG而filterCallback为null，无法构造筛选界面");

    // 筛选对话框
    filterDialog = new RFilterDialog(new RFilterCallback() {
      public void buildConditions(RForm form) {
        filterCallback.buildConditions(form);
      }

      public void clearConditions() {
        filterCallback.clearConditions();
      }

      public void onQuery() {
        filterCallback.onQuery();
        pagingGrid.forceRefreshAndGotoFirstPage();
      }
    });

    // 筛选按钮
    filterButton = new RToolbarButton(RActionFactory.makeFilterAction(new ClickHandler() {
      public void onClick(ClickEvent event) {
        filterDialog.center();
      }
    }));
    toolbar.add(filterButton);
  }

  /**
   * 构造表格
   * 
   */
  private void buildGrid() {
    grid = new RGrid();
    grid.setShowRowSelector(true);
    grid.setSingleSelection(singleSelection);
    grid.setHoverRow(true);
    grid.addRGridClickListener(new GridListener());

    for (int i = 0; i < columnCaptions.length; i++) {
      grid.addColumnDef(new RGridColumnDef(columnCaptions[i]));
    }
    grid.setAllColumnsSortable(true);

    pagingGrid = new RPagingGrid(grid, new GridDataProvider());
    pagingGrid.getPagingBar().setShowPageSizeBox(false);
    pagingGrid.addRPagingGridListener(new PagingGridListener());
    root.add(pagingGrid);
  }

  /**
   * 设置标题
   * 
   * @param caption
   */
  public void setCaption(String caption) {
    setCaptionText(caption);
  }

  /**
   * 设置表格列标题
   * 
   * @param columnCaptions
   */
  public void setColumnCaptions(String[] columnCaptions) {
    this.columnCaptions = columnCaptions;
  }

  /**
   * 回调
   * 
   * @return
   */
  public RBrowserCallback getBrowserCallback() {
    return browserCallback;
  }

  /**
   * 设置回调
   * 
   * @param browserCallback
   */
  public void setBrowserCallback(RBrowserCallback browserCallback) {
    this.browserCallback = browserCallback;
  }

  /**
   * 筛选方式，取值范围为FILTER_STYLE_*，默认为{@link #FILTER_STYLE_NONE}
   * 
   * @return
   */
  public int getFilterStyle() {
    return filterStyle;
  }

  /**
   * 设置筛选方式，取值范围为FILTER_STYLE_*，默认为{@link #FILTER_STYLE_NONE}
   * <p>
   * <li>{@link #FILTER_STYLE_NONE} 不需要排序
   * <li>{@link #FILTER_STYLE_PANEL} 在工具栏下方显示一个筛选面板
   * <li>{@link #FILTER_STYLE_DIALOG}
   * 在工具栏上显示一个筛选按钮，点击筛选按钮后弹出筛选对话框
   * 
   * @param filterStyle
   */
  public void setFilterStyle(int filterStyle) {
    this.filterStyle = filterStyle;
  }

  /**
   * 筛选界面回调
   * 
   * @return
   */
  public RFilterCallback getFilterCallback() {
    return filterCallback;
  }

  /**
   * 设置筛选界面回调
   * 
   * @param filterCallback
   * @see {@link RBrowserWithFilterCallback}
   */
  public void setFilterCallback(RFilterCallback filterCallback) {
    this.filterCallback = filterCallback;
  }

  /**
   * 是否只能单选，默认为true
   * 
   * @return
   */
  public boolean isSingleSelection() {
    return singleSelection;
  }

  /**
   * 设置是否只能单选，默认为true。singleSelection为true时，RBrowserCallback.
   * onSelected返回的对象是用户所选行对应的对象;
   * singleSelection为false时，RBrowserCallback
   * .onSelected返回的对象是所有用户所选行对应的对象组成的一个ArrayList;
   * 
   * @param singleSelection
   */
  public void setSingleSelection(boolean singleSelection) {
    if (this.singleSelection == singleSelection)
      return;

    this.singleSelection = singleSelection;
    grid.setSingleSelection(singleSelection);
    grid.rebuild();
  }

  public void show() {
    super.show();
    buildFilterUI();
    pagingGrid.forceRefreshAndGotoFirstPage();
  }

  public void hide() {
    super.hide();
    grid.clearHoverRowStyle();
  }

  /**
   * 每页记录数，默认为{@link #DEFAULT_PAGE_SIZE}
   * 
   * @return
   */
  public int getPageSize() {
    return pagingGrid.getProvider().getPageSize();
  }

  /**
   * 设置每页记录数
   * 
   * @param pageSize
   */
  public void setPageSize(int pageSize) {
    pagingGrid.getProvider().setPageSize(pageSize);
  }

  /**
   * 表格数据提供者
   * 
   * @author LiQi
   * 
   */
  private class GridDataProvider extends RGridPageDataProvider {

    public GridDataProvider() {
      setPageSize(RBrowserDialog.DEFAULT_PAGE_SIZE);
    }

    public void doFetch(int page, final AsyncCallback callback) {
      String sortField = grid.getSortColumnDef() == null ? null : grid.getSortColumnDef()
          .getCaption();
      String sortDir = grid.getSortColumnDef() == null ? null : grid.getSortColumnDef().getSort();
      browserCallback.fetchData(page, getPageSize(), sortField, sortDir, callback);
    }

    public Object getData(int row, int col) {
      if (row >= getRowCount())
        return "";

      return browserCallback.displayData(getValues().get(row), col);
    }
  }

  /**
   * 确定按钮事件处理
   * 
   * @author LiQi
   * 
   */
  private class OKButtonHandler implements ClickHandler {
    public void onClick(ClickEvent event) {
      if (grid.getSelections() == null || grid.getSelections().size() == 0) {
        RMsgBox.showError("请选择一行");
        return;
      }

      hide();
      if (singleSelection)
        browserCallback.onSelected(pagingGrid.getSelections().get(0));
      else
        browserCallback.onSelected(pagingGrid.getSelections());
    }
  }

  /**
   * 表格点击事件处理
   * 
   * @author LiQi
   * 
   */
  private class GridListener implements RGridClickListener {

    public void onClick(RGrid grid, RGridColumnDef colDef, int row, int col, Widget sender) {
      // 点击标题行的不处理，点击复选框的不处理，多选时也不处理
      if (row < grid.getHeaderRowCount() || sender != null)
        return;

      if (singleSelection) {
        // 单选时单击行即返回
        hide();
        browserCallback.onSelected(pagingGrid.getProvider().getValues().get(
            row - grid.getHeaderRowCount()));
      } else {
        // 多选时单击行即选中或取消选中当前行
        if (grid.isRowSelected(row))
          grid.deselectRow(row);
        else
          grid.selectRow(row);
      }
    }
  }

  /**
   * 翻页表格事件处理
   * 
   * @author LiQi
   * 
   */
  private class PagingGridListener implements RPagingGridListener {

    /** 确保重新居中只执行一次 */
    private boolean reCentered = false;

    public void onPageLoad(RPagingGrid sender) {
      // 数据加载完成后表格的大小会发生变化，需要使对话框重新居中，但只执行一次，避免每次翻页是对话框的位置都会变动
      if (!reCentered) {
        center();
        reCentered = true;
      }

      // 数据为空时把确定按钮禁用
      okButton.setEnabled(pagingGrid.getProvider().getTotalCount() > 0);
    }
  }
}
